/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 * util.c
 * Copyright (C) Maxim Ermilov 2009 <zaspire@rambler.ru>
 *
 * util.c is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * util.c is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <libanjuta/anjuta-shell.h>
#include <libanjuta/interfaces/ianjuta-indicable.h>
#include <libanjuta/interfaces/ianjuta-editor.h>
#include <libanjuta/interfaces/ianjuta-project-manager.h>
#include <libanjuta/anjuta-session.h>

#include "plugin.h"
#include "util.h"

#define HIGHLIGHT_MISSEDSEMICOLON "javascript.missed"

GList *
getJSIncludePaths ()
{
	const gchar *project_root = NULL;
	GList *ret = NULL;
	ret = g_list_append (ret, g_strdup (GJS_PATH));

	anjuta_shell_get (ANJUTA_PLUGIN (getPlugin ())->shell,
					  IANJUTA_PROJECT_MANAGER_PROJECT_ROOT_URI,
					  G_TYPE_STRING, &project_root, NULL);

	GFile *tmp = g_file_new_for_uri (project_root);
	AnjutaSession *session = anjuta_session_new (g_file_get_path (tmp));
	g_object_unref (tmp);
	
	GList* dir_list = anjuta_session_get_string_list (session, "options", "js_dirs");
	GList *i;
	for (i = dir_list; i; i = g_list_next (i))
	{
		g_assert (i->data != NULL);
		ret = g_list_append (ret, i->data);
	}
	if (!dir_list)
	{
		ret = g_list_append (ret, ".");
		anjuta_session_set_string_list (session, "options", "js_dirs", ret);
	}
	return ret;
}

gpointer plugin = NULL;

gpointer
getPlugin ()
{
	if (plugin)
		return plugin;
	g_assert_not_reached ();
	return NULL;
}

void
setPlugin (gpointer pl)
{
	plugin = pl;
}

IJsSymbol*
global_search (const gchar *name)
{
	JSLang* plugin = (JSLang*)getPlugin ();
	return ijs_symbol_get_member (plugin->symbol, name);
}

void
highlight_lines (GList *lines)
{
	JSLang* plugin = (JSLang*)getPlugin ();

	if (!plugin->prefs)
		plugin->prefs = anjuta_shell_get_preferences (ANJUTA_PLUGIN (plugin)->shell, NULL);

	if (!anjuta_preferences_get_bool (plugin->prefs, HIGHLIGHT_MISSEDSEMICOLON))
	{
		DEBUG_PRINT ("JSLang: Highlight missed semicolon off");
		return;
	}

	IAnjutaEditor *editor = ((JSLang*)getPlugin ())->current_editor;
	if (!IANJUTA_IS_EDITOR (editor))
		return;
	IAnjutaIndicable *indicable = IANJUTA_INDICABLE (editor);
	if (!indicable)
		return;

	ianjuta_indicable_clear (indicable, NULL);

	GList *i;
	for (i = lines; i; i = g_list_next (i))
	{
		if (!i->data)
			continue;
		gint line = GPOINTER_TO_INT (i->data);
		IAnjutaIterable* begin = ianjuta_editor_get_line_begin_position (editor, line, NULL);

		IAnjutaIterable *end = ianjuta_editor_get_line_end_position (editor, line, NULL);
		ianjuta_indicable_set (indicable, begin, end, TRUE, NULL);
	}
}

enum code_state
{
	STATE_CODE,
	STATE_QSTR,
	STATE_STR,
	STATE_ONE_LINE_COMMENT,
	STATE_COMMENT
};


gboolean
code_is_in_comment_or_str (gchar *str, gboolean remove_not_code)
{
	g_assert (str != NULL);
	int s;
	gchar *i;
	for (i = str, s = STATE_CODE; *i != '\0'; i++)
	{
		switch (s)
		{
			case STATE_CODE:
				if (*i == '"')
				{
					s = STATE_QSTR;
					i++;
					break;
				}
				if (*i == '\'')
				{
					s = STATE_STR;
					i++;
					break;
				}
				if (*i == '/' && *(i + 1) == '*')
				{
					if (remove_not_code)
						*i = ' ';
					i++;
					s = STATE_COMMENT;
					break;
				}
				if (*i == '/' && *(i + 1) == '/')
				{
					if (remove_not_code)
						*i = ' ';
					i++;
					s = STATE_ONE_LINE_COMMENT;
					break;
				}
				break;
			case STATE_QSTR:
				if (*i == '\\' && *(i + 1) == '"')
				{
					if (remove_not_code)
						*i = ' ';
					i++;
					break;
				}
				if (*i == '"')
					s = STATE_CODE;
				break;
			case STATE_STR:
				if (*i == '\\' && *(i + 1) == '\'')
				{
					if (remove_not_code)
						*i = ' ';
					i++;
					break;
				}
				if (*i == '\'')
					s = STATE_CODE;
				break;
			case STATE_ONE_LINE_COMMENT:
				if (*i == '\n')
					s = STATE_CODE;
				break;
			case STATE_COMMENT:
				if (*i == '*' && *(i + 1) == '/')
				{
					if (remove_not_code)
						*i = ' ';
					i++;
					if (remove_not_code)
						*i = ' ';
					s = STATE_CODE;
				}
				break;
			default:
				g_assert_not_reached ();
		}
		if (s != STATE_CODE && remove_not_code)
			*i = ' ';
	}
	return s != STATE_CODE;
}

